﻿using System;
using System.IO;
using System.Net;
using System.Diagnostics;

namespace Twitter
{
	internal enum HttpMethod
	{
		Get,
		Delete,
		Post,
		Put,
	}

	/// <summary>
	/// Caches cookies and credentials and ensures all new 
	/// requests created with <see cref="CreateRequest"/> get 
	/// them properly.
	/// </summary>
	internal class AuthenticatedEndpoint
	{
		ICredentials credentials;
		CookieContainer cookies = new CookieContainer();

		static AuthenticatedEndpoint()
		{
			//NEED THIS NOW TO FIX ERROR 417 
			System.Net.ServicePointManager.Expect100Continue = false;
		}

		public AuthenticatedEndpoint(ICredentials credentials)
		{
			this.credentials = credentials;
		}

		/// <summary>
		/// Creates a request to the given endpoint.
		/// </summary>
		public WebRequest CreateRequest(Uri uri)
		{
			WebRequest request = WebRequest.Create(uri);
			HttpWebRequest http = request as HttpWebRequest;
			if (http != null)
			{
				// don't reuse the container so that we 
				// don't have session cookies... causes 
				// problems with caching??
				//http.CookieContainer = cookies;
			}
			request.Credentials = credentials;
			return request;
		}

		/// <summary>
		/// Executes the given Uri by doing a POST and reading the response.
		/// </summary>
		/// <param name="getUrl"></param>
		public string Execute(Uri url, HttpMethod method)
		{
			WebRequest request = CreateRequest(url);
			request.Method = method.ToString().ToUpper();
			Tracer.TraceInformation(typeof(AuthenticatedEndpoint), "About to execute {0} for {1}", request.Method, url);

			try
			{
				using (WebResponse response = request.GetResponse())
				using (Stream responseStream = response.GetResponseStream())
				using (StreamReader reader = new StreamReader(responseStream))
				{
					string result = reader.ReadToEnd();
					return result;
				}
			}
			catch (WebException wex)
			{
				// TODO: improve error parsing.
				string responseError = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd();
				Tracer.TraceError(typeof(AuthenticatedEndpoint), wex, "Failed to execute {0} for {1}. Response was:\n{2}",
					request.Method,
					url,
					responseError);
				throw;
			}
			catch (Exception ex)
			{
				Tracer.TraceError(typeof(AuthenticatedEndpoint), ex, "Failed to execute {0} for {1}", request.Method, url);
				throw;
			}
		}


		public ICredentials Credentials
		{
			get { return credentials; }
		}

		#region Unused

		//private void NullRequestAction(WebRequest request)
		//{
		//}

		//private void NullResponseAction(WebResponse response)
		//{
		//    using (Stream responseStream = response.GetResponseStream())
		//    using (StreamReader reader = new StreamReader(responseStream))
		//    {
		//        // TODO: handle error response.
		//        string result = reader.ReadToEnd();
		//    }
		//}

		//public void Execute(Uri uri,
		//    Action<WebRequest> requestAction,
		//    Action<WebResponse> responseAction)
		//{
		//    Guard.ArgumentNotNull(requestAction, "requestAction");
		//    Guard.ArgumentNotNull(responseAction, "responseAction");

		//    WebRequest request = CreateRequest(uri);

		//    requestAction(request);

		//    using (WebResponse response = request.GetResponse())
		//    {
		//        responseAction(response);
		//    }
		//}

		//public void Execute(Uri uri)
		//{
		//    Execute(uri, NullRequestAction, NullResponseAction);
		//}

		//public void Execute(Uri uri, Action<WebRequest> requestAction)
		//{
		//    Execute(uri, requestAction, NullResponseAction);
		//}

		//public void Execute(Uri uri, Action<WebResponse> responseAction)
		//{
		//    Execute(uri, NullRequestAction, responseAction);
		//}

		//public TResult Execute<TResult>(Uri uri, 
		//    Action<WebRequest> requestAction,
		//    Func<WebResponse, TResult> responseAction)
		//{
		//    Guard.ArgumentNotNull(requestAction, "requestAction");
		//    Guard.ArgumentNotNull(responseAction, "responseAction");

		//    WebRequest request = CreateRequest(uri);

		//    requestAction(request);

		//    using (WebResponse response = request.GetResponse())
		//    {
		//        return responseAction(response);
		//    }
		//}

		//public TResult Execute<TResult>(Uri uri,
		//    Func<WebResponse, TResult> responseAction)
		//{
		//    return Execute<TResult>(uri, NullRequestAction, responseAction);
		//}

		//public WebRequest CreateRequest(string uriString)
		//{
		//    return CreateRequest(new Uri(uriString));
		//}

		#endregion
	}
}
